
package com.shop.cloud.mall.api.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
import com.alipay.easysdk.util.generic.models.AlipayOpenApiGenericResponse;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.getui.push.v2.sdk.common.ApiResult;
import com.getui.push.v2.sdk.dto.req.Audience;
import com.getui.push.v2.sdk.dto.req.AudienceDTO;
import com.getui.push.v2.sdk.dto.req.message.PushChannel;
import com.getui.push.v2.sdk.dto.req.message.PushDTO;
import com.getui.push.v2.sdk.dto.req.message.PushMessage;
import com.getui.push.v2.sdk.dto.req.message.android.GTNotification;
import com.getui.push.v2.sdk.dto.req.message.ios.Alert;
import com.getui.push.v2.sdk.dto.req.message.ios.Aps;
import com.getui.push.v2.sdk.dto.req.message.ios.IosDTO;
import com.getui.push.v2.sdk.dto.res.TaskIdDTO;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingRequest;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingUnfreezeRequest;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingResult;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.shop.cloud.common.core.constant.CacheConstants;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.constant.SecurityConstants;
import com.shop.cloud.common.core.util.LocalDateTimeUtils;
import com.shop.cloud.common.core.util.R;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.common.getui.utils.GeTuiUtil;
import com.shop.cloud.common.portal.util.ApiUtil;
import com.shop.cloud.common.portal.util.ThirdSessionHolder;
import com.shop.cloud.common.sms.config.SmsConfigProperties;
import com.shop.cloud.common.sms.util.SmsUtils;
import com.shop.cloud.mall.api.mapper.*;
import com.shop.cloud.mall.api.service.*;
import com.shop.cloud.mall.common.constant.MallConstants;
import com.shop.cloud.mall.common.constant.MallReturnCode;
import com.shop.cloud.mall.common.dto.PlaceOrderDTO;
import com.shop.cloud.mall.common.dto.PlaceOrderSkuDTO;
import com.shop.cloud.mall.common.entity.*;
import com.shop.cloud.mall.common.enums.OrderItemEnum;
import com.shop.cloud.mall.common.enums.OrderLogisticsEnum;
import com.shop.cloud.mall.common.enums.OrderInfoEnum;
import com.shop.cloud.pay.common.entity.ProfitSharingReceiver;
import com.shop.cloud.weixin.common.feign.FeignWxTemplateMsgService;
import com.shop.cloud.pay.common.constant.PayConstants;
import com.shop.cloud.pay.common.dto.AliBaseRequest;
import com.shop.cloud.pay.common.entity.PayConfig;
import com.shop.cloud.upms.common.entity.SysConfigSms;
import com.shop.cloud.upms.common.entity.SysConfigSmsTemplates;
import com.shop.cloud.upms.common.entity.SysUser;
import com.shop.cloud.upms.common.feign.FeignConfigSmsService;
import com.shop.cloud.upms.common.feign.FeignUserService;
import com.shop.cloud.weixin.common.constant.WxConstant;
import com.shop.cloud.weixin.common.dto.WxTemplateMsgSendDTO;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.klock.annotation.Klock;
import org.springframework.boot.autoconfigure.klock.model.LockTimeoutStrategy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 商城订单
 *
 * @author
 * @date 2019-09-10 15:21:22
 */
@Slf4j
@Service
@AllArgsConstructor
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

	private final GoodsSkuMapper goodsSkuMapper;
	private final GoodsSpuService goodsSpuService;
	private final GoodsSkuService goodsSkuService;
	private final OrderItemService orderItemService;
	private final GoodsSkuSpecValueMapper goodsSkuSpecValueMapper;
	private final ShoppingCartService shoppingCartService;
	private final OrderLogisticsService orderLogisticsService;
	private final UserAddressService userAddressService;
	private final RedisTemplate<String, String> redisTemplate;
	private final OrderLogisticsDetailService orderLogisticsDetailService;
	private final PointsRecordService pointsRecordService;
	private final UserInfoService userInfoService;
	private final com.shop.cloud.pay.common.feign.FeignPayService feignPayService;
	private final CouponUserService couponUserService;
	private final BargainUserMapper bargainUserMapper;
	private final GrouponInfoMapper grouponInfoMapper;
	private final GrouponUserMapper grouponUserMapper;
	private final FeignWxTemplateMsgService feignWxTemplateMsgService;
	private final ShopInfoService shopInfoService;
	private final SeckillInfoService seckillInfoService;
	private final SeckillHallInfoService seckillHallInfoService;
	private final SeckillHallService seckillHallService;
	private final UserShopService userShopService;
	private final UserRecordService userRecordService;
	private final DistributionConfigService distributionConfigService;
	private final DistributionUserService distributionUserService;
	private final DistributionOrderService distributionOrderService;
	private final DistributionOrderItemService distributionOrderItemService;
	private final BargainCutService bargainCutService;
	private final FeignConfigSmsService feignConfigSmsService;
	private final FeignUserService feignUserService;
	private final OrderBillMapper orderBillMapper;
	private final OrderProfitSharingService orderProfitSharingService;
	private final GeTuiUtil geTuiUtil;
	private final UserBalanceService userBalanceService;
	private final UserBalanceRecordService userBalanceRecordService;
	private final UserPointsService userPointsService;
	private final VipUserService vipUserService;

	@Override
	public IPage<OrderInfo> page2(IPage<OrderInfo> page, OrderInfo orderInfo) {
		return baseMapper.selectPage2(page,orderInfo);
	}

	@Override
	public OrderInfo getById2(Serializable id) {
		OrderInfo orderInfo = baseMapper.selectById2(id);
		if(orderInfo != null){
			String keyRedis = null;
			//获取自动取消倒计时
			if(CommonConstants.NO.equals(orderInfo.getIsPay())){
				keyRedis = String.valueOf(StrUtil.format("{}:{}::{}", TenantContextHolder.getTenantId(), CacheConstants.MALL_ORDER_KEY_IS_PAY_0, orderInfo.getId()));
			}
			//获取自动收货倒计时
			if(OrderInfoEnum.STATUS_2.getValue().equals(orderInfo.getStatus())){
				keyRedis = String.valueOf(StrUtil.format("{}:{}::{}", TenantContextHolder.getTenantId(), CacheConstants.MALL_ORDER_KEY_STATUS_2, orderInfo.getId()));
			}
			if(keyRedis != null){
				Long outTime = redisTemplate.getExpire(keyRedis);
				if(outTime != null && outTime > 0){
					orderInfo.setOutTime(outTime);
				}
			}
		}
		return orderInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void orderCancel(OrderInfo orderInfo) {
		if(CommonConstants.NO.equals(orderInfo.getIsPay()) && !OrderInfoEnum.STATUS_5.getValue().equals(orderInfo.getStatus())){//校验
			//实时查询订单是否已支付
			WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
			ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
			if(shopInfo != null){
				//微信支付
				if(StrUtil.isNotBlank(shopInfo.getWxMchId())){
					request.setTransactionId(orderInfo.getTransactionId());
					request.setOutTradeNo(orderInfo.getOrderNo());
					request.setSubMchId(shopInfo.getWxMchId());
					R<WxPayOrderQueryResult> r = feignPayService.queryOrderWx(request, SecurityConstants.FROM_IN);
					if(r.isOk()){
						WxPayOrderQueryResult wxPayOrderQueryResult = r.getData();
						if(!WxPayConstants.WxpayTradeStatus.NOTPAY.equals(wxPayOrderQueryResult.getTradeState())){//只有未支付的订单能取消，已支付订单完成回调逻辑
							orderInfo.setTradeType(wxPayOrderQueryResult.getTradeType());
							if(orderInfo.getPaymentPrice().multiply(new BigDecimal(100)).intValue() == wxPayOrderQueryResult.getTotalFee()){
								String timeEnd = wxPayOrderQueryResult.getTimeEnd();
								LocalDateTime paymentTime = LocalDateTimeUtils.parse(timeEnd);
								orderInfo.setPaymentTime(paymentTime);
								orderInfo.setTransactionId(wxPayOrderQueryResult.getTransactionId());
								orderInfo.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_1);
								this.notifyOrder(orderInfo);
							}else{
								throw new RuntimeException("该订单已支付，付款金额与订单金额不等");
							}
						}
					}
				}
				//支付宝
				if(StrUtil.isNotBlank(shopInfo.getAliAuthToken())){
					AliBaseRequest aliBaseRequest = new AliBaseRequest();
					Map<String, Object> params = new HashMap<>();
					params.put("outTradeNo",orderInfo.getOrderNo());
					aliBaseRequest.setAppAuthToken(shopInfo.getAliAuthToken());
					aliBaseRequest.setParams(params);
					R<AlipayTradeQueryResponse> r = feignPayService.queryOrderAli(aliBaseRequest, SecurityConstants.FROM_IN);
					if(r.isOk()){
						AlipayTradeQueryResponse alipayTradeQueryResponse = r.getData();
						if(PayConstants.ALI_RES_CODE_SUCCESS.equals(alipayTradeQueryResponse.getCode())
								&& ("TRADE_SUCCESS".equals(alipayTradeQueryResponse.getTradeStatus())
								||"TRADE_FINISHED".equals(alipayTradeQueryResponse.getTradeStatus()))){//只有未支付的订单能取消，已支付订单完成回调逻辑
							if(orderInfo.getPaymentPrice().compareTo(new BigDecimal(alipayTradeQueryResponse.getTotalAmount())) == 0){
								LocalDateTime paymentTime = LocalDateTimeUtils.parse(alipayTradeQueryResponse.getSendPayDate());
								orderInfo.setPaymentTime(paymentTime);
								orderInfo.setTransactionId(alipayTradeQueryResponse.getTradeNo());
								orderInfo.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_2);
								this.notifyOrder(orderInfo);
							}else{
								throw new RuntimeException("该订单已支付，付款金额与订单金额不等");
							}
						}
					}
				}
			}
			orderInfo.setStatus(OrderInfoEnum.STATUS_5.getValue());
			//回滚库存
			List<OrderItem> listOrderItem = orderItemService.list(Wrappers.<OrderItem>lambdaQuery()
					.eq(OrderItem::getOrderId,orderInfo.getId()));
			listOrderItem.forEach(orderItem -> {
				GoodsSku goodsSku = goodsSkuMapper.selectById(orderItem.getSkuId());
				if(goodsSku != null){
					goodsSku.setStock(goodsSku.getStock() + orderItem.getQuantity());
					if(!goodsSkuService.updateById(goodsSku)){//更新库存
						throw new RuntimeException("请重新提交");
					}
				}
				//回滚积分
				PointsRecord pointsRecord = new PointsRecord();
				pointsRecord.setRecordType(MallConstants.POINTS_RECORD_TYPE_4);
				pointsRecord.setOrderItemId(orderItem.getId());
				pointsRecord = pointsRecordService.getOne(Wrappers.query(pointsRecord));
				//查询该订单详情是否有抵扣积分
				if(pointsRecord !=null && StrUtil.isNotBlank(pointsRecord.getId())){
					//减回赠送的积分
					pointsRecord.setId(null);
					pointsRecord.setTenantId(null);
					pointsRecord.setCreateTime(null);
					pointsRecord.setUpdateTime(null);
					pointsRecord.setShopId(orderItem.getShopId());
					pointsRecord.setDescription("【订单取消】 " + pointsRecord.getDescription());
					pointsRecord.setAmount(- pointsRecord.getAmount());
					pointsRecord.setRecordType(MallConstants.POINTS_RECORD_TYPE_5);
					//新增积分记录
					pointsRecordService.save(pointsRecord);
					//加回抵扣积分
					userPointsService.updateUserPoints(orderInfo.getUserId(), pointsRecord.getAmount(), false);
				}
				//回滚秒杀已售数量
				if(MallConstants.ORDER_TYPE_3.equals(orderInfo.getOrderType())){
					SeckillInfo seckillInfo = seckillInfoService.getById(orderInfo.getMarketId());
					seckillInfo.setSeckillNum(seckillInfo.getSeckillNum()-1);
					if(!seckillInfoService.updateById(seckillInfo)){//更新秒杀已售数量
						throw new RuntimeException("请重新提交");
					}
				}
			});
			baseMapper.updateById(orderInfo);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void orderReceive(OrderInfo orderInfo) {
		orderInfo.setStatus(OrderInfoEnum.STATUS_3.getValue());
		orderInfo.setAppraisesStatus(MallConstants.APPRAISES_STATUS_0);
		orderInfo.setReceiverTime(LocalDateTime.now());
		baseMapper.updateById(orderInfo);

		ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
		//分销订单
		List<DistributionOrder> listDistributionOrder = distributionOrderService.list(Wrappers.<DistributionOrder>lambdaQuery()
				.eq(DistributionOrder::getOrderId, orderInfo.getId()));
		//支付金额大于0的支付宝或微信支付
		if((MallConstants.ORDER_PAYMENT_TYPE_1.equals(orderInfo.getPaymentType()) || MallConstants.ORDER_PAYMENT_TYPE_2.equals(orderInfo.getPaymentType()))
		&& orderInfo.getPaymentPrice().compareTo(BigDecimal.ZERO) == 1){
			//分账逻辑
			R<PayConfig> r = feignPayService.getPayConfigByType(orderInfo.getPaymentType(), SecurityConstants.FROM_IN);
			if(!r.isOk()){
				throw new RuntimeException(r.getMsg());
			}
			PayConfig payConfig = r.getData();
			if(payConfig == null){
				throw new RuntimeException("支付未配置");
			}
			//服务商并已开户了分账则进行解冻分账
			if(PayConstants.PAY_MODEL_1.equals(payConfig.getModel()) && CommonConstants.YES.equals(payConfig.getDividedEnable())){
				List<OrderProfitSharing> listOrderProfitSharing = new ArrayList<>();
				//分账服务费金额 = 支付金额*(服务费（%）/100)
				BigDecimal amountServiceFee = orderInfo.getPaymentPrice().multiply(shopInfo.getServiceFee().divide(BigDecimal.valueOf(100)));
				//分账分销拥金金额 = 分销订单返佣金额之和
				BigDecimal amountCommission = listDistributionOrder.stream().map(DistributionOrder::getCommission).reduce(BigDecimal.ZERO,BigDecimal::add);
				if(MallConstants.ORDER_PAYMENT_TYPE_1.equals(orderInfo.getPaymentType())){//微信支付
					//分账
					List<ProfitSharingReceiver> receivers = new ArrayList<>();
					ProfitSharingRequest request = new ProfitSharingRequest();
					request.setAppid(payConfig.getAppId());
					request.setTransactionId(orderInfo.getTransactionId());
					request.setOutOrderNo(orderInfo.getOrderNo());
					request.setSubMchId(shopInfo.getWxMchId());
					ProfitSharingReceiver profitSharingReceiver = new ProfitSharingReceiver();
					profitSharingReceiver.setAccount(payConfig.getDividedReceiptAccount());
					profitSharingReceiver.setType(payConfig.getDividedReceiptType());
					profitSharingReceiver.setName(payConfig.getDividedReceiptName());
					profitSharingReceiver.setAmount(0L);
					//分账抽取服务费
					if(shopInfo.getServiceFee().compareTo(BigDecimal.ZERO) == 1){
						profitSharingReceiver.setAmount(amountServiceFee.multiply(BigDecimal.valueOf(100)).longValue());
						profitSharingReceiver.setDescription("商城服务费");
						//分账订单
						OrderProfitSharing orderProfitSharing = new OrderProfitSharing();
						orderProfitSharing.setOrderId(orderInfo.getId());
						orderProfitSharing.setShopId(orderInfo.getShopId());
						orderProfitSharing.setPaymentType(orderInfo.getPaymentType());
						orderProfitSharing.setDividedReceiptType(payConfig.getDividedReceiptType());
						orderProfitSharing.setDividedReceiptAccount(payConfig.getDividedReceiptAccount());
						orderProfitSharing.setDividedReceiptName(payConfig.getDividedReceiptName());
						orderProfitSharing.setAmount(amountServiceFee);
						orderProfitSharing.setDescription("商城服务费");
						listOrderProfitSharing.add(orderProfitSharing);
					}
					//分账抽出订单产生的分销拥金
					if(amountCommission.compareTo(BigDecimal.ZERO) == 1){
						profitSharingReceiver.setAmount(profitSharingReceiver.getAmount()+amountCommission.multiply(BigDecimal.valueOf(100)).longValue());
						profitSharingReceiver.setDescription(profitSharingReceiver.getDescription() != null ? profitSharingReceiver.getDescription()+"+分销拥金" : "分销拥金");
						//分账订单
						OrderProfitSharing orderProfitSharing = new OrderProfitSharing();
						orderProfitSharing.setOrderId(orderInfo.getId());
						orderProfitSharing.setShopId(orderInfo.getShopId());
						orderProfitSharing.setPaymentType(orderInfo.getPaymentType());
						orderProfitSharing.setDividedReceiptType(payConfig.getDividedReceiptType());
						orderProfitSharing.setDividedReceiptAccount(payConfig.getDividedReceiptAccount());
						orderProfitSharing.setDividedReceiptName(payConfig.getDividedReceiptName());
						orderProfitSharing.setAmount(amountCommission);
						orderProfitSharing.setDescription("分销拥金");
						listOrderProfitSharing.add(orderProfitSharing);
					}
					if(profitSharingReceiver.getAmount() > 0){
						receivers.add(profitSharingReceiver);
					}
					request.setReceivers(JSONUtil.toJsonStr(receivers));
					if(receivers.size() > 0){
						//入库分销订单
						orderProfitSharingService.saveBatch(listOrderProfitSharing);

						//进行分账，单次分账请求按照传入的分账接收方账号和资金进行分账，同时会将订单剩余的待分账金额解冻给特约商户。故操作成功后，订单不能再进行分账，也不能进行分账完结。
						R<ProfitSharingResult> r2= feignPayService.profitSharingWx(request, SecurityConstants.FROM_IN);
						if(!r2.isOk()){
							throw new RuntimeException(r2.getMsg());
						}
					}else{
						//无分账金额，则完结分账
						ProfitSharingUnfreezeRequest profitSharingFinishRequest = new ProfitSharingUnfreezeRequest();
						profitSharingFinishRequest.setAppid(payConfig.getAppId());
						profitSharingFinishRequest.setTransactionId(orderInfo.getTransactionId());
						profitSharingFinishRequest.setOutOrderNo(orderInfo.getOrderNo());
						profitSharingFinishRequest.setSubMchId(shopInfo.getWxMchId());
						profitSharingFinishRequest.setDescription("无分账，解冻");
						feignPayService.profitSharingFinishWx(profitSharingFinishRequest, SecurityConstants.FROM_IN);
					}
				}else if(MallConstants.ORDER_PAYMENT_TYPE_2.equals(orderInfo.getPaymentType())) {//支付宝
					AliBaseRequest aliBaseRequest = new AliBaseRequest();
					Map<String, Object> params = new HashMap<>();
					params.put("out_request_no",orderInfo.getOrderNo());
					params.put("trade_no",orderInfo.getTransactionId());
					List<Map<String, Object>> royaltyParameters = new ArrayList();
					//分账抽取服务费
					if(shopInfo.getServiceFee().compareTo(BigDecimal.ZERO) == 1){
						Map<String, Object> royaltyParameter = new HashMap<>();
						royaltyParameter.put("trans_in_type", payConfig.getDividedReceiptType());
						royaltyParameter.put("trans_in", payConfig.getDividedReceiptAccount());
						royaltyParameter.put("trans_in_name", payConfig.getDividedReceiptName());
						royaltyParameter.put("amount", amountServiceFee);
						royaltyParameter.put("royalty_scene", "商城服务费");
						royaltyParameters.add(royaltyParameter);
						//分账订单
						OrderProfitSharing orderProfitSharing = new OrderProfitSharing();
						orderProfitSharing.setOrderId(orderInfo.getId());
						orderProfitSharing.setShopId(orderInfo.getShopId());
						orderProfitSharing.setPaymentType(orderInfo.getPaymentType());
						orderProfitSharing.setDividedReceiptType(payConfig.getDividedReceiptType());
						orderProfitSharing.setDividedReceiptAccount(payConfig.getDividedReceiptAccount());
						orderProfitSharing.setDividedReceiptName(payConfig.getDividedReceiptName());
						orderProfitSharing.setAmount(amountServiceFee);
						orderProfitSharing.setDescription((String) royaltyParameter.get("royalty_scene"));
						listOrderProfitSharing.add(orderProfitSharing);
					}
					//分账抽出订单产生的分销拥金
					if(amountCommission.compareTo(BigDecimal.ZERO) == 1){
						Map<String, Object> royaltyParameter = new HashMap<>();
						royaltyParameter.put("trans_in_type", payConfig.getDividedReceiptType());
						royaltyParameter.put("trans_in", payConfig.getDividedReceiptAccount());
						royaltyParameter.put("trans_in_name", payConfig.getDividedReceiptName());
						royaltyParameter.put("amount", amountCommission);
						royaltyParameter.put("royalty_scene", "分销拥金");
						royaltyParameters.add(royaltyParameter);
						//分账订单
						OrderProfitSharing orderProfitSharing = new OrderProfitSharing();
						orderProfitSharing.setOrderId(orderInfo.getId());
						orderProfitSharing.setShopId(orderInfo.getShopId());
						orderProfitSharing.setPaymentType(orderInfo.getPaymentType());
						orderProfitSharing.setDividedReceiptType(payConfig.getDividedReceiptType());
						orderProfitSharing.setDividedReceiptAccount(payConfig.getDividedReceiptAccount());
						orderProfitSharing.setDividedReceiptName(payConfig.getDividedReceiptName());
						orderProfitSharing.setAmount(amountCommission);
						orderProfitSharing.setDescription((String) royaltyParameter.get("royalty_scene"));
						listOrderProfitSharing.add(orderProfitSharing);
					}
					//入库分销订单
					orderProfitSharingService.saveBatch(listOrderProfitSharing);

					params.put("royalty_parameters", royaltyParameters);
					Map<String, Object> extendParams = new HashMap<>();
					//支付宝无完结分账接口，传入分账完结标识（royalty_finish=true），则本次分账成功后会自动将剩余资金解冻
					extendParams.put("royalty_finish", "true");
					params.put("extend_params", extendParams);
					aliBaseRequest.setAppAuthToken(shopInfo.getAliAuthToken());
					aliBaseRequest.setParams(params);
					R<AlipayOpenApiGenericResponse> r2= feignPayService.profitSharingAli(aliBaseRequest, SecurityConstants.FROM_IN);
					if(!r2.isOk()){
						throw new RuntimeException(r2.getMsg());
					}
				}
			}
		}
		//分销订单
		DistributionConfig distributionConfig = distributionConfigService.getOne(Wrappers.emptyWrapper());
		listDistributionOrder.forEach(distributionOrder -> {
			//分销订单加入redis，冻结时间自动解冻
			String keyRedis = String.valueOf(StrUtil.format("{}:{}::{}", TenantContextHolder.getTenantId(), CacheConstants.MALL_DISTRIBUTION_ORDER_THAW, distributionOrder.getId()));
			redisTemplate.opsForValue().set(keyRedis, distributionOrder.getId() , distributionConfig.getFrozenTime() , TimeUnit.HOURS);//设置过期时间
		});
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean removeById(Serializable id) {
		orderItemService.remove(Wrappers.<OrderItem>lambdaQuery()
				.eq(OrderItem::getOrderId,id));//删除订单详情
		return super.removeById(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public OrderInfo orderAddOne(HttpServletRequest request, PlaceOrderDTO placeOrderDTO) {
		SeckillInfo seckillInfo = null;
		//秒杀订单处理
		if(MallConstants.ORDER_TYPE_3.equals(placeOrderDTO.getOrderType())){
			seckillInfo = seckillInfoService.getById(placeOrderDTO.getMarketId());
			if(seckillInfo.getLimitNum() <= seckillInfo.getSeckillNum()){
				throw new RuntimeException(MallReturnCode.ERR_80031.getMsg());
			}
			//查出当前用户已经购买该秒杀商品的次数
			long count = this.count(Wrappers.<OrderInfo>lambdaQuery()
					.eq(OrderInfo::getUserId,ThirdSessionHolder.getUserId())
					.eq(OrderInfo::getOrderType,MallConstants.ORDER_TYPE_3)
					.eq(OrderInfo::getMarketId,placeOrderDTO.getMarketId())
					.and(wrapper -> wrapper.ne(OrderInfo::getStatus,OrderInfoEnum.STATUS_5.getValue())
							.or()
							.isNull(OrderInfo::getStatus)));
			if(count >= seckillInfo.getEachLimitNum()){
				throw new RuntimeException(MallReturnCode.ERR_80030.getMsg());
			}
			//校验秒杀合法性
			long seckillHallInfoCount = seckillHallInfoService.count(Wrappers.<SeckillHallInfo>lambdaQuery()
					.eq(SeckillHallInfo::getSeckillHallId,placeOrderDTO.getRelationId())
					.eq(SeckillHallInfo::getSeckillInfoId,placeOrderDTO.getMarketId()));
			if(seckillHallInfoCount <= 0){
				throw new RuntimeException(MallReturnCode.ERR_80032.getMsg());
			}
			//校验秒杀时间
			SeckillHall seckillHall = seckillHallService.getById(placeOrderDTO.getRelationId());
			if(seckillHall.getHallTime() != LocalDateTime.now().getHour()){
				throw new RuntimeException(MallReturnCode.ERR_80033.getMsg());
			}
		}

		placeOrderDTO.setUserId(ThirdSessionHolder.getUserId());
		placeOrderDTO.setAppId(ThirdSessionHolder.getThirdSession().getAppId());
		placeOrderDTO.setAppType(ApiUtil.getClientType(request));
		Map<String, PlaceOrderSkuDTO> mapSkuDTO = placeOrderDTO.getSkus().stream().collect(Collectors.toMap(PlaceOrderSkuDTO::getSkuId, Function.identity()));
		//查询出所有sku信息
		List<GoodsSku> listSku = goodsSkuMapper.listSkuInOrderSub(placeOrderDTO.getShopId(), placeOrderDTO.getSkus());
		//判断是否已经是店铺用户，否则加入listUserShop新增店铺用户
		UserShop userShop = new UserShop();
		userShop.setShopId(placeOrderDTO.getShopId());
		userShop.setUserId(placeOrderDTO.getUserId());
		long count = userShopService.count(Wrappers.query(userShop));
		if(count <= 0){
			userShopService.save(userShop);
		}
		OrderInfo orderInfo = new OrderInfo();
		BeanUtil.copyProperties(placeOrderDTO,orderInfo);
		orderInfo.setPaymentWay(MallConstants.PAYMENT_WAY_2);
		orderInfo.setShopId(placeOrderDTO.getShopId());
		orderInfo.setIsPay(CommonConstants.NO);
		orderInfo.setOrderNo(IdUtil.getSnowflake(0,0).nextIdStr());
		orderInfo.setSalesPrice(BigDecimal.ZERO);
		orderInfo.setPaymentPrice(BigDecimal.ZERO);
		orderInfo.setFreightPrice(BigDecimal.ZERO);
		orderInfo.setPaymentPoints(0);
		orderInfo.setPaymentCouponPrice(BigDecimal.ZERO);
		orderInfo.setPaymentUserGradeDiscountPrice(BigDecimal.ZERO);
		orderInfo.setPaymentVipDiscountPrice(BigDecimal.ZERO);
		orderInfo.setPaymentPointsPrice(BigDecimal.ZERO);
		orderInfo.setCreateTime(LocalDateTime.now());
		List<OrderItem> listOrderItem = new ArrayList<>();
		List<GoodsSku> listGoodsSku = new ArrayList<>();
		List<CouponUser> listCouponUser = new ArrayList<>();
		List<PointsRecord> listPointsRecord = new ArrayList<>();
		listSku.forEach(goodsSku -> {
			PlaceOrderSkuDTO placeOrderSkuDTO  = mapSkuDTO.get(goodsSku.getId());
			if(placeOrderSkuDTO == null){
				throw new RuntimeException("参数错误");
			}
			if(goodsSku != null){
				GoodsSpu goodsSpu = goodsSku.getGoodsSpu();
				//只有已上架和审核通过的商品能下单
				if(goodsSpu != null && CommonConstants.YES.equals(goodsSpu.getShelf()) && MallConstants.GOODS_STATUS_1.equals(goodsSpu.getVerifyStatus())){
					OrderItem orderItem = new OrderItem();
					orderItem.setOrderId(orderInfo.getId());
					orderItem.setShopId(orderInfo.getShopId());
					orderItem.setStatus(OrderItemEnum.STATUS_0.getValue());
					orderItem.setIsRefund(CommonConstants.NO);
					orderItem.setSpuId(goodsSpu.getId());
					orderItem.setSkuId(goodsSku.getId());
					orderItem.setSpuName(goodsSpu.getName());
					orderItem.setPicUrl(StrUtil.isNotBlank(goodsSku.getPicUrl()) ? goodsSku.getPicUrl() : goodsSpu.getPicUrls()[0]);
					orderItem.setQuantity(placeOrderSkuDTO.getQuantity());
					orderItem.setSupplierId(goodsSpu.getSupplierId());
					orderItem.setSalesPrice(goodsSku.getSalesPrice());
					if(MallConstants.DELIVERY_WAY_1.equals(orderInfo.getDeliveryWay())){//快递配送要算运费
						orderItem.setFreightPrice(placeOrderSkuDTO.getFreightPrice());
					}else{//自提配送不算运费
						orderItem.setFreightPrice(BigDecimal.ZERO);
					}
					orderItem.setPaymentPrice(placeOrderSkuDTO.getPaymentPrice().add(orderItem.getFreightPrice()));
					orderItem.setPaymentPoints(placeOrderSkuDTO.getPaymentPoints());
					orderItem.setPaymentCouponPrice(placeOrderSkuDTO.getPaymentCouponPrice());
					orderItem.setPaymentPointsPrice(placeOrderSkuDTO.getPaymentPointsPrice());
					orderItem.setPaymentUserGradeDiscountPrice(placeOrderSkuDTO.getPaymentUserGradeDiscountPrice());
					orderItem.setPaymentVipDiscountPrice(placeOrderSkuDTO.getPaymentVipDiscountPrice());
					orderItem.setCouponUserId(placeOrderSkuDTO.getCouponUserId());

					//校验参数（数量、金额）合法性
					verifyOrderItem(orderInfo, orderItem, goodsSku);

					BigDecimal quantity = new BigDecimal(placeOrderSkuDTO.getQuantity());
					if(StrUtil.isNotBlank(orderItem.getCouponUserId())){
						//校验电子券
						CouponUser couponUser = couponUserService.getById(orderItem.getCouponUserId());
						if(couponUser == null){
							throw new RuntimeException("非法优惠券");
						}
						if(!MallConstants.COUPON_USER_STATUS_0.equals(couponUser.getStatus())){
							throw new RuntimeException("优惠券已经使用");
						}
						if(couponUser.getValidBeginTime().isAfter(LocalDateTime.now())){
							throw new RuntimeException("优惠券未在使用期");
						}
						if(couponUser.getValidEndTime().isBefore(LocalDateTime.now())){
							throw new RuntimeException("优惠券已过期");
						}
						couponUser.setStatus(MallConstants.COUPON_USER_STATUS_1);
						couponUser.setUsedTime(LocalDateTime.now());
						listCouponUser.add(couponUser);
					}
					List<GoodsSkuSpecValue> listGoodsSkuSpecValue = goodsSkuSpecValueMapper.listGoodsSkuSpecValueBySkuId(goodsSku.getId());
					listGoodsSkuSpecValue.forEach(goodsSkuSpecValue -> {
						String specInfo = orderItem.getSpecInfo();
						specInfo = StrUtil.isNotBlank(specInfo) ? specInfo : "";
						orderItem.setSpecInfo(specInfo
								+ goodsSkuSpecValue.getSpecValueName()
								+  "，" );
					});
					String specInfo = orderItem.getSpecInfo();
					if(StrUtil.isNotBlank(specInfo)){
						orderItem.setSpecInfo(specInfo.substring(0,specInfo.length() - 1));
					}
					listOrderItem.add(orderItem);
					orderInfo.setSalesPrice(orderInfo.getSalesPrice().add(goodsSku.getSalesPrice().multiply(quantity)));
					orderInfo.setFreightPrice(orderInfo.getFreightPrice().add(orderItem.getFreightPrice()));
					orderInfo.setPaymentPrice(orderInfo.getPaymentPrice().add(orderItem.getPaymentPrice()));
					orderInfo.setPaymentPoints(orderInfo.getPaymentPoints() + (orderItem.getPaymentPoints() != null ? orderItem.getPaymentPoints() : 0));
					orderInfo.setPaymentCouponPrice(orderInfo.getPaymentCouponPrice().add((orderItem.getPaymentCouponPrice() != null ? orderItem.getPaymentCouponPrice() : BigDecimal.ZERO)));
					orderInfo.setPaymentUserGradeDiscountPrice(orderInfo.getPaymentUserGradeDiscountPrice().add((orderItem.getPaymentUserGradeDiscountPrice() != null ? orderItem.getPaymentUserGradeDiscountPrice() : BigDecimal.ZERO)));
					orderInfo.setPaymentPointsPrice(orderInfo.getPaymentPointsPrice().add((orderItem.getPaymentPointsPrice() != null ? orderItem.getPaymentPointsPrice() : BigDecimal.ZERO)));
					orderInfo.setPaymentVipDiscountPrice(orderInfo.getPaymentVipDiscountPrice().add((orderItem.getPaymentVipDiscountPrice() != null ? orderItem.getPaymentVipDiscountPrice() : BigDecimal.ZERO)));
					goodsSku.setStock(goodsSku.getStock() - orderItem.getQuantity());
					listGoodsSku.add(goodsSku);
					//删除购物车
					shoppingCartService.remove(Wrappers.<ShoppingCart>lambdaQuery()
							.eq(ShoppingCart::getSpuId,goodsSpu.getId())
							.eq(ShoppingCart::getSkuId,goodsSku.getId())
							.eq(ShoppingCart::getUserId,placeOrderDTO.getUserId()));
				}
			}
		});
		if(listOrderItem.size() > 0 && listGoodsSku.size()>0){
			if(MallConstants.DELIVERY_WAY_1.equals(orderInfo.getDeliveryWay())){//配送方式1、普通快递的订单要新增订单物流
				UserAddress userAddress = userAddressService.getById(placeOrderDTO.getUserAddressId());
				orderInfo.setRecName(userAddress.getUserName());
				orderInfo.setRecTel(userAddress.getTelNum());
				orderInfo.setRecAddress(userAddress.getProvinceName()+userAddress.getCityName()+userAddress.getCountyName()+userAddress.getDetailInfo());
				orderInfo.setAreaId(userAddress.getAreaId());
			}
			orderInfo.setName(listOrderItem.get(0).getSpuName());
			super.save(orderInfo);//保存订单
			//订单发票入库
			OrderBill orderBill = placeOrderDTO.getOrderBill();
			if(orderBill != null){
				orderBill.setBillAmount(orderInfo.getPaymentPrice());
				orderBill.setBillStatus(MallConstants.BILL_STATUS_1);
				orderBill.setShopId(orderInfo.getShopId());
				orderBill.setOrderId(orderInfo.getId());
				orderBillMapper.insert(orderBill);
			}
			listOrderItem.forEach(orderItem -> orderItem.setOrderId(orderInfo.getId()));
			//保存订单详情
			orderItemService.saveBatch(listOrderItem);
			//修改用户电子券状态
			if(listCouponUser != null && listCouponUser.size() > 0){
				couponUserService.updateBatchById(listCouponUser);
			}
			listOrderItem.forEach(orderItem -> {
				if(orderItem.getPaymentPoints() != null && orderItem.getPaymentPoints() > 0){
					//处理积分抵扣
					PointsRecord pointsRecord = new PointsRecord();
					pointsRecord.setShopId(orderItem.getShopId());
					pointsRecord.setUserId(orderInfo.getUserId());
					pointsRecord.setDescription("【抵扣】购买商品【" + orderItem.getSpuName() + "】 * " +orderItem.getQuantity());
					pointsRecord.setSpuId(orderItem.getSpuId());
					pointsRecord.setOrderItemId(orderItem.getId());
					pointsRecord.setRecordType(MallConstants.POINTS_RECORD_TYPE_4);
					pointsRecord.setAmount(- orderItem.getPaymentPoints());
					listPointsRecord.add(pointsRecord);
				}
			});
			listGoodsSku.forEach(goodsSkuItem -> {
				if(!goodsSkuService.updateById(goodsSkuItem)){//更新库存
					throw new RuntimeException("请重新提交");
				}
			});

			//订单自动取消时间
			long orderTimeOut = MallConstants.ORDER_TIME_OUT_0;
			//秒杀订单处理
			if(MallConstants.ORDER_TYPE_3.equals(placeOrderDTO.getOrderType())){
				orderTimeOut = MallConstants.ORDER_TIME_OUT_0_SECKILL;
				seckillInfo.setSeckillNum(seckillInfo.getSeckillNum()+1);
				if(!seckillInfoService.updateById(seckillInfo)){//更新秒杀已售数量
					throw new RuntimeException("请重新提交");
				};
			}
			if(orderInfo.getPaymentPoints() > 0){
				//新增积分记录
				pointsRecordService.saveBatch(listPointsRecord);
				//更新用户积分
				UserPoints userPoints = userPointsService.getById(orderInfo.getUserId());
				if(userPoints.getPointsCurrent() < orderInfo.getPaymentPoints()){
					throw new RuntimeException("积分不足");
				}
				userPointsService.updateUserPoints(orderInfo.getUserId(), -orderInfo.getPaymentPoints(), false);
			}
			//加入redis，30分钟自动取消
			String keyRedis = String.valueOf(StrUtil.format("{}:{}::{}", TenantContextHolder.getTenantId(), CacheConstants.MALL_ORDER_KEY_IS_PAY_0, orderInfo.getId()));
			redisTemplate.opsForValue().set(keyRedis, orderInfo.getOrderNo() , orderTimeOut , TimeUnit.MINUTES);//设置过期时间
		}
		return orderInfo;
	}
	@Override
	@Transactional(rollbackFor = Exception.class)
	public List<OrderInfo> orderAddMap(HttpServletRequest request, Map<String, PlaceOrderDTO> mapPlaceOrderDTO) {
		List<OrderInfo> rs = new ArrayList<>();
		mapPlaceOrderDTO.forEach((shopId, placeOrderDTO) -> {
			placeOrderDTO.setShopId(shopId);
			rs.add(this.orderAddOne(request, placeOrderDTO));
		});
		return rs;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	//加锁防止支付平台同时发多次回调
	@Klock(name = "notifyOrder", keys = {"#orderInfo.getId()"}, lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
	public void notifyOrder(OrderInfo orderInfo) {
		if(CommonConstants.NO.equals(orderInfo.getIsPay())){//只有未支付订单能操作
			orderInfo.setIsPay(CommonConstants.YES);
			orderInfo.setStatus(OrderInfoEnum.STATUS_1.getValue());
			List<OrderItem> listOrderItem = orderItemService.list(Wrappers.<OrderItem>lambdaQuery()
					.eq(OrderItem::getOrderId,orderInfo.getId()));
			Map<String, List<OrderItem>> resultList = listOrderItem.stream().collect(Collectors.groupingBy(OrderItem::getSpuId));
			AtomicReference<Integer> pointsGiveAmount = new AtomicReference<>(0);
			List<PointsRecord> listPointsRecord = new ArrayList<>();
			List<GoodsSpu> listGoodsSpu = goodsSpuService.listByIds(resultList.keySet());
			listGoodsSpu.forEach(goodsSpu -> {
				resultList.get(goodsSpu.getId()).forEach(orderItem -> {
					//更新销量
					goodsSpu.setSaleNum(goodsSpu.getSaleNum()+orderItem.getQuantity());
					//处理积分赠送
					if(CommonConstants.YES.equals(goodsSpu.getPointsGiveSwitch())){
						PointsRecord pointsRecord = new PointsRecord();
						pointsRecord.setShopId(orderItem.getShopId());
						pointsRecord.setUserId(orderInfo.getUserId());
						pointsRecord.setDescription("【赠送】购买商品【" + goodsSpu.getName() + "】 * " +orderItem.getQuantity());
						pointsRecord.setSpuId(goodsSpu.getId());
						pointsRecord.setOrderItemId(orderItem.getId());
						pointsRecord.setRecordType(MallConstants.POINTS_RECORD_TYPE_2);
						pointsRecord.setAmount(orderItem.getQuantity() * goodsSpu.getPointsGiveNum());
						listPointsRecord.add(pointsRecord);
						pointsGiveAmount.updateAndGet(v -> v + orderItem.getQuantity() * goodsSpu.getPointsGiveNum());
					}
				});
				goodsSpuService.updateById1(goodsSpu);
			});
			//新增积分记录
			pointsRecordService.saveBatch(listPointsRecord);
			//更新用户积分
			userPointsService.updateUserPoints(orderInfo.getUserId(), pointsGiveAmount.get(), true);
			//更新会员用户累积折扣金额
			if(orderInfo.getPaymentVipDiscountPrice().compareTo(BigDecimal.ZERO) == 1){
				vipUserService.updateTotalDiscountAmount(orderInfo.getUserId(), orderInfo.getPaymentVipDiscountPrice());
			}

			//更新用户消费记录：总计订单数、总计消费金额
			UserRecord userRecord = userRecordService.getById(orderInfo.getUserId());
			//判断是否已有消费记录，没有则先新增
			if(userRecord == null){
				userRecord = new UserRecord();
				userRecord.setUserId(orderInfo.getUserId());
				userRecordService.save(userRecord);
			}
			userRecordService.updateTotalAmount(orderInfo.getUserId(),orderInfo.getPaymentPrice());
			userRecordService.updateTotalOrder(orderInfo.getUserId(),1);

			//处理砍价订单，更新砍价记录
			if(MallConstants.ORDER_TYPE_1.equals(orderInfo.getOrderType())){
				BargainUser bargainUser = bargainUserMapper.selectById(orderInfo.getRelationId());
				bargainUser.setIsBuy(CommonConstants.YES);
				bargainUser.setOrderId(orderInfo.getId());
				bargainUserMapper.updateById(bargainUser);
			}
			//处理拼团订单
			if(MallConstants.ORDER_TYPE_2.equals(orderInfo.getOrderType())){
				GrouponInfo grouponInfo = grouponInfoMapper.selectById(orderInfo.getMarketId());
				UserInfo userInfo = userInfoService.getById(orderInfo.getUserId());
				//新增拼团记录
				GrouponUser grouponUser = new GrouponUser();
				grouponUser.setShopId(grouponInfo.getShopId());
				grouponUser.setGrouponId(grouponInfo.getId());
				grouponUser.setGroupId(orderInfo.getMarketId());
				grouponUser.setUserId(orderInfo.getUserId());
				grouponUser.setNickName(userInfo.getNickName());
				grouponUser.setHeadimgUrl(userInfo.getHeadimgUrl());
				grouponUser.setSpuId(grouponInfo.getSpuId());
				grouponUser.setSkuId(grouponInfo.getSkuId());
				grouponUser.setGrouponNum(grouponInfo.getGrouponNum());
				grouponUser.setGrouponPrice(grouponInfo.getGrouponPrice());
				grouponUser.setStatus(MallConstants.GROUPON_USER_STATUS_0);
				grouponUserMapper.insert(grouponUser);
				if(StrUtil.isBlank(orderInfo.getRelationId())){//新团，当前用户为团长
					grouponUser.setValidBeginTime(orderInfo.getPaymentTime());
					grouponUser.setValidEndTime(orderInfo.getPaymentTime().plusHours(grouponInfo.getDuration()));
					grouponUser.setIsLeader(CommonConstants.YES);
					grouponUser.setGroupId(grouponUser.getId());
					orderInfo.setRelationId(grouponUser.getId());
					orderInfo.setStatus(OrderInfoEnum.STATUS_10.getValue());
				}else{
					grouponUser.setGroupId(orderInfo.getRelationId());
					grouponUser.setIsLeader(CommonConstants.NO);
					//查出团长拼团记录
					GrouponUser grouponUser2 = grouponUserMapper.selectById(orderInfo.getRelationId());
					grouponUser.setValidBeginTime(grouponUser2.getValidBeginTime());
					grouponUser.setValidEndTime(grouponUser2.getValidEndTime());
					Integer count = grouponUserMapper.selectCountGrouponing(orderInfo.getRelationId()) + 1;
					if(count == grouponUser2.getGrouponNum()){//已满成团
						GrouponUser grouponUser3 = new GrouponUser();
						grouponUser.setStatus(MallConstants.GROUPON_USER_STATUS_1);
						grouponUser3.setStatus(MallConstants.GROUPON_USER_STATUS_1);
						grouponUserMapper.update(grouponUser3, Wrappers.<GrouponUser>lambdaQuery()
								.eq(GrouponUser::getGroupId, grouponUser2.getId()));
						//更新团里所有订单状态
						OrderInfo orderInfo1 = new OrderInfo();
						orderInfo1.setStatus(OrderInfoEnum.STATUS_1.getValue());
						baseMapper.update(orderInfo1, Wrappers.<OrderInfo>lambdaQuery()
								.eq(OrderInfo::getRelationId, grouponUser2.getId())
								.eq(OrderInfo::getStatus, OrderInfoEnum.STATUS_10.getValue()));
					}else if(count > grouponUser2.getGrouponNum()){//满团开新团
						grouponUser.setValidBeginTime(orderInfo.getPaymentTime());
						grouponUser.setValidEndTime(orderInfo.getPaymentTime().plusHours(grouponInfo.getDuration()));
						grouponUser.setIsLeader(CommonConstants.YES);
						grouponUser.setGroupId(grouponUser.getId());
						orderInfo.setRelationId(grouponUser.getId());
						orderInfo.setStatus(OrderInfoEnum.STATUS_10.getValue());
					}else{//未满入团
						orderInfo.setStatus(OrderInfoEnum.STATUS_10.getValue());
					}
				}
				grouponUser.setOrderId(orderInfo.getId());
				grouponUserMapper.updateById(grouponUser);
				grouponInfo.setLaunchNum(grouponInfo.getLaunchNum()+1);//参与人数+1
				grouponInfoMapper.updateById(grouponInfo);
			}
			baseMapper.updateById(orderInfo);//更新订单

			if(MallConstants.ORDER_TYPE_0.equals(orderInfo.getOrderType())){//普通订单才参与分销
				//分销逻辑
				DistributionConfig distributionConfig = distributionConfigService.getByTenantId(TenantContextHolder.getTenantId());
				if(distributionConfig != null && CommonConstants.YES.equals(distributionConfig.getEnable())){//判断是否已开启分销
					//获取订单用户信息
					UserInfo userInfo = userInfoService.getById(orderInfo.getUserId());
					//如果分销模式为满额分销，在此判断当前用户是否能成为分销员
					if(MallConstants.DISTRIBUTION_MODEL_3.equals(distributionConfig.getDistributionModel())){
						//先判断当前用户是否已经成为分销员
						DistributionUser distributionUser = distributionUserService.getById(userInfo.getId());
						if(distributionUser == null){
							//还不是分销员，获取用户的消费记录
							UserRecord userRecord1 = userRecordService.getById(userInfo.getId());
							if(userRecord1 != null){
								//判断用户总计消费金额是否大于等于指定额度
								if(userRecord1.getTotalAmount().compareTo(distributionConfig.getFullAmount()) >= 0){
									//用户总计消费金额大于等于指定额度，则将当前用户设为分销员
									distributionUser = new DistributionUser();
									distributionUser.setUserId(userInfo.getId());
									distributionUserService.save(distributionUser);
								}
							}
						}
					}
					//判断订单用户是否有上级
					if(StrUtil.isNotBlank(userInfo.getParentId())){
						DistributionUser distributionUser1 = distributionUserService.getById(userInfo.getParentId());
						//判断订单用户上级是否是分销员
						if(distributionUser1 != null){
							//一级返利
							DistributionOrder distributionOrder1 = new DistributionOrder();
							distributionOrder1.setDistributionLevel(MallConstants.DISTRIBUTION_LEVEL_1);
							distributionOrder1.setDistributionUserId(distributionUser1.getUserId());
							distributionOrder1.setUserId(userInfo.getId());
							distributionOrder1.setOrderId(orderInfo.getId());
							distributionOrder1.setShopId(orderInfo.getShopId());
							distributionOrder1.setCommissionStatus(MallConstants.DISTRIBUTION_COMMISSION_STATUS_1);
							distributionOrder1.setCommission(BigDecimal.ZERO);
							List<DistributionOrderItem> listDistributionOrderItem1 = new ArrayList<>();
							listOrderItem.forEach(orderItem1 -> {
								//获取sku信息
								GoodsSku goodsSku1 = goodsSkuService.getById(orderItem1.getSkuId());
								//计算此订单明细的返利金额
								BigDecimal commission1 = BigDecimal.valueOf(goodsSku1.getFirstRebate()).divide(BigDecimal.valueOf(100)).multiply(orderItem1.getPaymentPrice());
								if(commission1.compareTo(BigDecimal.ZERO) == 1){//返利金额大于0才入库
									DistributionOrderItem distributionOrderItem1 = new DistributionOrderItem();
									distributionOrderItem1.setDistributionOrderId(distributionOrder1.getId());
									distributionOrderItem1.setOrderId(orderItem1.getOrderId());
									distributionOrderItem1.setOrderItemId(orderItem1.getId());
									distributionOrderItem1.setCommission(commission1);
									listDistributionOrderItem1.add(distributionOrderItem1);
									distributionOrder1.setCommission(distributionOrder1.getCommission().add(commission1));
								}
							});
							if(distributionOrder1.getCommission().compareTo(BigDecimal.ZERO) == 1){//返利金额大于0才入库
								//新增分销订单
								distributionOrderService.save(distributionOrder1);
								//批量新增分销订单明细
								listDistributionOrderItem1.forEach(distributionOrderItem1 -> {
									distributionOrderItem1.setDistributionOrderId(distributionOrder1.getId());
								});
								distributionOrderItemService.saveBatch(listDistributionOrderItem1);
								//更新分销员累计佣金金额
								distributionUserService.updateCommissionTotal(distributionUser1.getUserId(),distributionOrder1.getCommission());
							}
						}
						//获取一级用户信息
						UserInfo userInfo1 = userInfoService.getById(userInfo.getParentId());
						//判断一级用户是否有上级
						if(userInfo1 != null && StrUtil.isNotBlank(userInfo1.getParentId())){
							DistributionUser distributionUser2 = distributionUserService.getById(userInfo1.getParentId());
							//判断一级用户上级是否是分销员
							if(distributionUser2 != null){
								//二级返利
								DistributionOrder distributionOrder2 = new DistributionOrder();
								distributionOrder2.setDistributionLevel(MallConstants.DISTRIBUTION_LEVEL_2);
								distributionOrder2.setDistributionUserId(distributionUser2.getUserId());
								distributionOrder2.setUserId(userInfo.getId());
								distributionOrder2.setOrderId(orderInfo.getId());
								distributionOrder2.setShopId(orderInfo.getShopId());
								distributionOrder2.setCommissionStatus(MallConstants.DISTRIBUTION_COMMISSION_STATUS_1);
								distributionOrder2.setCommission(BigDecimal.ZERO);
								List<DistributionOrderItem> listDistributionOrderItem2 = new ArrayList<>();
								listOrderItem.forEach(orderItem2 -> {
									//获取sku信息
									GoodsSku goodsSku2 = goodsSkuService.getById(orderItem2.getSkuId());
									//计算此订单明细的返利金额
									BigDecimal commission2 = BigDecimal.valueOf(goodsSku2.getSecondRebate()).divide(BigDecimal.valueOf(100)).multiply(orderItem2.getPaymentPrice());
									if(commission2.compareTo(BigDecimal.ZERO) == 1) {//返利金额大于0才入库
										DistributionOrderItem distributionOrderItem2 = new DistributionOrderItem();
										distributionOrderItem2.setDistributionOrderId(distributionOrder2.getId());
										distributionOrderItem2.setOrderId(orderItem2.getOrderId());
										distributionOrderItem2.setOrderItemId(orderItem2.getId());
										distributionOrderItem2.setCommission(commission2);
										listDistributionOrderItem2.add(distributionOrderItem2);
										distributionOrder2.setCommission(distributionOrder2.getCommission().add(commission2));
									}
								});
								if(distributionOrder2.getCommission().compareTo(BigDecimal.ZERO) == 1){//返利金额大于0才入库
									//新增分销订单
									distributionOrderService.save(distributionOrder2);
									//批量新增分销订单明细
									listDistributionOrderItem2.forEach(distributionOrderItem2 -> {
										distributionOrderItem2.setDistributionOrderId(distributionOrder2.getId());
									});
									distributionOrderItemService.saveBatch(listDistributionOrderItem2);
									//更新分销员累计佣金金额
									distributionUserService.updateCommissionTotal(distributionUser2.getUserId(),distributionOrder2.getCommission());
								}
							}
						}
					}
				}
			}

			//发送微信订阅、模板消息给商城用户
			try {
				WxTemplateMsgSendDTO wxTemplateMsgSendDTO = new WxTemplateMsgSendDTO();
				wxTemplateMsgSendDTO.setMallUserId(orderInfo.getUserId());
				wxTemplateMsgSendDTO.setUseType(WxConstant.WX_TMP_USE_TYPE_2);
				wxTemplateMsgSendDTO.setPage("pages/order/order-detail/index?id="+orderInfo.getId());
				Map<String, Object> data = new HashMap();
				Map<String, Object> map = BeanUtil.beanToMap(orderInfo);
				for(String mapKey: map.keySet()){
					data.put("order." + mapKey, map.get(mapKey));
				}
				wxTemplateMsgSendDTO.setData(data);
				feignWxTemplateMsgService.sendTemplateMsgMa(wxTemplateMsgSendDTO, SecurityConstants.FROM_IN);
				feignWxTemplateMsgService.sendTemplateMsgMp(wxTemplateMsgSendDTO, SecurityConstants.FROM_IN);
			}catch (Exception e){
				log.error("发送微信订阅、模板消息出错："+e.getMessage(), e);
			}

			//发送短信通知店员用户
			try {
				//获取短信配置
				SysConfigSms sysConfigSms = feignConfigSmsService.getSysConfigSms(SecurityConstants.FROM_IN).getData();
				if(sysConfigSms != null){
					Map map = new HashMap<>();
					ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
					map.put("shopName", shopInfo.getName());
					//获取所有可发送短信的用户手机号码
					SysUser sysUser = new SysUser();
					sysUser.setSmsSwitchOrder(CommonConstants.YES);
					sysUser.setShopId(orderInfo.getShopId());
					List<SysUser> listSysUser = feignUserService.getInsideUserList(sysUser, SecurityConstants.FROM_IN).getData();
					if(listSysUser != null && listSysUser.size() > 0){
						String phoneNumbers = listSysUser.stream().map(SysUser::getPhone).collect(Collectors.joining(","));
						SysConfigSmsTemplates sysConfigSmsTemplates = JSONUtil.toBean(sysConfigSms.getTemplates(),SysConfigSmsTemplates.class);
						SmsConfigProperties smsConfigProperties = new SmsConfigProperties();
						BeanUtil.copyProperties(sysConfigSms, smsConfigProperties);
						//批量发送短信
						SmsUtils.sendSms(smsConfigProperties, sysConfigSmsTemplates.getSignName5(),
								phoneNumbers,
								sysConfigSmsTemplates.getTemplateCode5(),
								JSONUtil.toJsonStr(map)
						);
					}
				}
			} catch (Exception e) {
				log.error("发送短信通知店员用户出错："+e.getMessage(), e);
			}

			//发送个推消息推送给店员用户
			try {
				Alert alert = new Alert();
				alert.setTitle("发货提醒");
				alert.setBody("有新订单，请及时发货");
				Aps aps = new Aps();
				aps.setAlert(alert);
				IosDTO iosDTO = new IosDTO();
				iosDTO.setPayload("订单推送");
				iosDTO.setAps(aps);
				PushChannel pushChannel = new PushChannel();
				pushChannel.setIos(iosDTO);
				//创建消息体
				GTNotification notification = new GTNotification();
				notification.setClickType("startapp");
				notification.setTitle("发货提醒");
				notification.setBody("有新订单，请及时发货");
				PushMessage pushMessage = new PushMessage();
				pushMessage.setNotification(notification);
				PushDTO<Audience> pushDTO = new PushDTO();
				pushDTO.setPushMessage(pushMessage);
				pushDTO.setPushChannel(pushChannel);
				ApiResult createMsgResult = geTuiUtil.createMsg(pushDTO);
				if(createMsgResult.getCode() == 0){
					TaskIdDTO taskIdDTO = (TaskIdDTO) createMsgResult.getData();
					String taskid = taskIdDTO.getTaskId();
					//获取所有可发送消息推送的用户信息；拼接出openIM中的用户ID，即个推中的别名
					SysUser sysUser = new SysUser();
					sysUser.setPushSwitchOrder(CommonConstants.YES);
					sysUser.setShopId(orderInfo.getShopId());
					List<SysUser> listSysUser = feignUserService.getInsideUserList(sysUser, SecurityConstants.FROM_IN).getData();
					if(listSysUser != null && listSysUser.size() > 0){
						List<String> listAlias = listSysUser.stream().map(sysUser1 ->{
							String alias = TenantContextHolder.getTenantId() + "B" + sysUser1.getId();
							return alias;
						}).collect(Collectors.toList());
						//根据别名批量推送
						Audience audience = new Audience();
						audience.setAlias(listAlias);
						AudienceDTO audienceDTO = new AudienceDTO();
						audienceDTO.setTaskid(taskid);
						audienceDTO.setAudience(audience);
						ApiResult apiResult = geTuiUtil.pushListByAlias(audienceDTO);
						if(apiResult.getCode() != 0){
							log.error("发送个推消息推送给店员用户出错：" + apiResult.getMsg());
						}
					}
				}else{
					log.error("发送个推消息推送给店员用户创建消息体出错：" + createMsgResult.getMsg());
				}
			} catch (Exception e) {
				log.error("发送个推消息推送给店员用户出错："+e.getMessage(), e);
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void notifyLogisticsr(JSONObject jsonObject) {
		JSONObject lastResultJSONObject = jsonObject.getJSONObject("lastResult");
		List<OrderLogistics> orderLogisticsList = orderLogisticsService.list(Wrappers.<OrderLogistics>lambdaQuery()
				.eq(OrderLogistics::getLogisticsCode,lastResultJSONObject.getStr("com"))
				.eq(OrderLogistics::getLogisticsNo,lastResultJSONObject.getStr("nu")));
		if(orderLogisticsList != null && orderLogisticsList.size() > 0){
			orderLogisticsList.forEach(orderLogistics -> {
				String status = jsonObject.getStr("status");
				if("abort".equals(status)){//中止
					orderLogistics.setStatus(OrderLogisticsEnum.STATUS_ER.getValue());
					orderLogistics.setMessage(jsonObject.getStr("message"));
				}else{
					orderLogisticsDetailService.remove(Wrappers.<OrderLogisticsDetail>lambdaQuery()
							.eq(OrderLogisticsDetail::getLogisticsId,orderLogistics.getId()));//先删除
					JSONObject jsonResult =(JSONObject) jsonObject.get("lastResult");
					orderLogistics.setStatus(jsonResult.getStr("state"));
					orderLogistics.setIsCheck(jsonResult.getStr("ischeck"));
					JSONArray jSONArray = jsonResult.getJSONArray("data");
					List<OrderLogisticsDetail> listOrderLogisticsDetail = new ArrayList<>();
					jSONArray.forEach(object -> {
						JSONObject jsonData = JSONUtil.parseObj(object);
						OrderLogisticsDetail orderLogisticsDetail = new OrderLogisticsDetail();
						orderLogisticsDetail.setLogisticsId(orderLogistics.getId());
						orderLogisticsDetail.setLogisticsTime(LocalDateTimeUtils.parse(jsonData.getStr("time")));
						orderLogisticsDetail.setLogisticsInformation(jsonData.getStr("context"));
						listOrderLogisticsDetail.add(orderLogisticsDetail);
					});
					orderLogisticsDetailService.saveBatch(listOrderLogisticsDetail);
					//获取最近一条物流信息
					Optional<OrderLogisticsDetail> orderLogisticsDetail = listOrderLogisticsDetail.stream().collect(Collectors.maxBy(Comparator.comparing(OrderLogisticsDetail::getLogisticsTime)));
					orderLogistics.setMessage(orderLogisticsDetail.get().getLogisticsInformation());
				}
				orderLogisticsService.updateById(orderLogistics);
			});
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void balancePay(OrderInfo orderInfo) {
		//更新用户余额
		userBalanceService.updateTotalAmount(orderInfo.getUserId(), orderInfo.getPaymentPrice().negate());
		//新增余额记录
		UserBalanceRecord userBalanceRecord = new UserBalanceRecord();
		userBalanceRecord.setIsPay(CommonConstants.YES);
		userBalanceRecord.setAmount(orderInfo.getPaymentPrice().negate());
		userBalanceRecord.setUserId(orderInfo.getUserId());
		userBalanceRecord.setType(MallConstants.USER_BALANCE_RECORD_TYPE_3);
		userBalanceRecord.setRelationId(orderInfo.getId());
		userBalanceRecordService.save(userBalanceRecord);
		//回调支付
		orderInfo.setPaymentTime(LocalDateTime.now());
		this.notifyOrder(orderInfo);
	}

	/**
	 * 校验参数（数量、金额）合法性
	 * @param orderInfo
	 * @param orderItem
	 * @param goodsSku
	 */
	public void verifyOrderItem(OrderInfo orderInfo, OrderItem orderItem, GoodsSku goodsSku){
		//校验参数（数量、金额）合法性
		if(orderItem.getQuantity() < 1){
			throw new RuntimeException("参数（orderItem.quantity）错误："+orderItem.getQuantity());
		}
		if(orderItem.getPaymentPrice().compareTo(BigDecimal.ZERO) == -1){
			throw new RuntimeException("参数（orderItem.paymentPrice）错误，支付价格不能小于0："+orderItem.getPaymentPrice());
		}
		//计算实际商品单价：(支付金额+积分抵扣金额+电子券抵扣金额+用户等级折扣金额+vip折扣金额-运费金额)/数量
		BigDecimal unitPrice = orderItem.getPaymentPrice()
				.add(orderItem.getPaymentCouponPrice() != null ? orderItem.getPaymentCouponPrice() : BigDecimal.ZERO)
				.add(orderItem.getPaymentPointsPrice() != null ? orderItem.getPaymentPointsPrice() : BigDecimal.ZERO)
				.add(orderItem.getPaymentUserGradeDiscountPrice() != null ? orderItem.getPaymentUserGradeDiscountPrice() : BigDecimal.ZERO)
				.add(orderItem.getPaymentVipDiscountPrice() != null ? orderItem.getPaymentVipDiscountPrice() : BigDecimal.ZERO)
				.subtract(orderItem.getFreightPrice() != null ? orderItem.getFreightPrice() : BigDecimal.ZERO);
		unitPrice = unitPrice.divide(BigDecimal.valueOf(orderItem.getQuantity()), 2, RoundingMode.HALF_UP);
		//普通订单
		if(StrUtil.isBlank(orderInfo.getOrderType()) || MallConstants.ORDER_TYPE_0.equals(orderInfo.getOrderType())){
			//比较计算单价和实际单价是否相等
			if(goodsSku.getSalesPrice().compareTo(unitPrice) != 0){
				log.error("商品单价:" + goodsSku.getSalesPrice());
				log.error("实际商品单价:" + unitPrice);
				throw new RuntimeException("参数（orderItem.paymentPrice）错误，计算单价和实际单价不相等");
			}
		}
		//秒杀订单
		if(MallConstants.ORDER_TYPE_3.equals(orderInfo.getOrderType())){
			SeckillInfo seckillInfo = seckillInfoService.getById(orderInfo.getMarketId());
			//校验金额
			if(seckillInfo.getSeckillPrice().compareTo(unitPrice) != 0){
				throw new RuntimeException("参数（orderItem.paymentPrice）错误，秒杀订单金额不正确");
			}
		}
		//砍价订单
		if(MallConstants.ORDER_TYPE_1.equals(orderInfo.getOrderType())){
			BargainUser bargainUser = bargainUserMapper.selectById(orderInfo.getRelationId());
			BigDecimal bayPrice;//砍价购买价格
			if(CommonConstants.YES.equals(bargainUser.getFloorBuy())){
				//必须底价购买（1：是），砍价购买价格 = 砍价底价
				bayPrice = bargainUser.getBargainPrice();
			}else{
				//必须底价购买（0：否），砍价购买价格 = 商品价格-已砍金额
				BigDecimal totalCutPrice = bargainCutService.getTotalCutPrice(orderInfo.getRelationId());
				bayPrice = goodsSku.getSalesPrice().subtract(totalCutPrice);
			}
			//校验金额
			if(bayPrice.compareTo(unitPrice) != 0){
				throw new RuntimeException("参数（orderItem.paymentPrice）错误，砍价订单金额不正确");
			}
		}
		//拼团订单
		if(MallConstants.ORDER_TYPE_2.equals(orderInfo.getOrderType())){
			GrouponInfo grouponInfo = grouponInfoMapper.selectById(orderInfo.getMarketId());
			//校验金额
			if(grouponInfo.getGrouponPrice().compareTo(unitPrice) != 0){
				throw new RuntimeException("参数（orderItem.paymentPrice）错误，拼团订单金额不正确");
			}
		}
	}
}
